<template>
  <div id="fullarea" :style="chartConfigStyle" :class="{'scroll-container':isFullscreen, 'theme-dark': !chartsTheme, 'theme-light': chartsTheme, 'total-app-container-mobile':showMobilePage }" class="total-app-container">
    <DashboardListTab ref="DashboardListTabRef" v-model="activeChartTab" :is-full-screen="getFullScreen()" @handleTabClick="handleTabClick" />
    <template v-if="activeChartTab !== -10 && !showMobilePage">
      <template v-if="canEdit">
        <div class="expand-btn-group">
          <div :style="{ 'margin-left': getFullScreen() ? 0 : sidebar.opened ? '184px' : '80px' }" class="system-group">
            <i :class="{ 'system-highlight': !editMobileMode }" class="el-icon-monitor" @click="toConfigMobile(true)"/>
            <i :class="{ 'system-highlight': editMobileMode }" class="el-icon-mobile-phone" @click="toConfigMobile(false)"/>
          </div>
          <div :style="{ 'left': getFullScreen() ? '78px' : '262px' }" class="switch-group flex-center" >
            <div :class="{ 'active': isShow }" class="item" @click="toggleShow(true)">已展示</div>
            <div :class="{ 'active': !isShow }" class="item" @click="toggleShow(false)">已隐藏</div>
            <div :style="{left: isShow ? '4px' : '60px'}" class="bg"/>
          </div>
          <el-button size="small" type="primary" @click="toCreatModule">
            新建图表<i class="el-icon-plus" style="margin-left: 4px" />
          </el-button>
          <MoreOpeator
            :list="[
              { label: '视图配置', handelClick: toEditConfig },
              { label: '清空图表', handelClick: toClear },
            ]"
            label="更多操作"
          />
          <el-button size="small" class="plain-btn" @click="saveEdit">保存</el-button>
          <el-button v-if="editMobileMode" size="small" class="plain-btn" @click="toCopyMobile">粘贴</el-button>
          <el-button size="small" class="quiet-btn" @click="cancelEdit">取消调整</el-button>
        </div>
      </template>
      <template v-else>
        <div v-show="isHideAdsorbBall" class="adsorb-btn" title="展开" @click="isHideAdsorbBall = false">
          <img :src="adsorbBtnIcon" alt="展开">
        </div>
        <div v-show="!isHideAdsorbBall" class="expand-btn-group">
          <el-button size="small" class="plain-btn" @click="switchFullscreen">
            <div class="flex-center">
              {{ getFullScreen() ? '退出全屏' : '全屏' }}
              <img :src="fullscreenBtnIcon" alt="">
            </div>
          </el-button>
          <!-- 筛选 -->
          <FilterPopover
            ref="filterPopoverRef"
            v-model="globalFilter"
            :tab-id="activeChartTab"
            is-global
            is-btn
            @handelAllChange="handelAllChange">
            <el-button slot="btnReference" plain size="small" class="plain-btn">
              <div class="flex-center">
                全局筛选<img :src="filterBtnIcon" alt="全局筛选">
              </div>
            </el-button>
          </FilterPopover>
          <el-button v-if="hasEditPermission" size="small" class="plain-btn" @click="handleEditClick">
            <div class="flex-center">
              调整布局<img :src="adjustBtnIcon" style="width: 14px; height: 14px" alt="">
            </div>
          </el-button>
          <div class="expend-btn" @click="isHideAdsorbBall = true">
            收起<i class="el-icon-arrow-up"/>
          </div>
        </div>
      </template>
    </template>
    <div v-if="!showMobilePage && editMobileMode" class="edit-mobile-mode">移动端模式</div>
    <ChatOverview v-if="activeChartTab === -10" :permission-denied="permissionDenied" :all-chart-tab="allChartTab" @tabClick="tabClick" @getTabList="getTabList"/>
    <template v-else>
      <div v-if="!layoutList || !layoutList.length" class="empty-card-container ">
        <el-card v-loading="listLoading" :body-style="{ padding: modulePadding + 'px' }" class="empty-card-wrap p20" shadow="hover">
          <p v-if="listLoading"/>
          <p v-else-if="hasEditPermission">
            <img :src="emptyImg" class="empty-img" alt="">
            尚未创建图表
          </p>
          <p v-else>
            <img :src="emptyImg" class="empty-img" alt="">
            尚未创建图表，请联系管理员
          </p>
        </el-card>
      </div>
      <grid-layout
        v-else
        ref="gridLayout"
        :layout.sync="layoutList"
        :col-num="girdLayoutCfg.colNum"
        :row-height="girdLayoutCfg.rowHeight"
        :max-rows="girdLayoutCfg.maxRows"
        :is-draggable="canEdit && girdLayoutCfg.isDraggable"
        :is-resizable="canEdit && girdLayoutCfg.isResizable"
        :is-mirrored="girdLayoutCfg.isMirrored"
        :auto-size="girdLayoutCfg.autoSize"
        :vertical-compact="girdLayoutCfg.verticalCompact"
        :use-css-transforms="girdLayoutCfg.useCssTransforms"
        :prevent-collision="girdLayoutCfg.preventCollision"
        :responsive="girdLayoutCfg.responsive"
        :breakpoints="girdLayoutCfg.breakpoints"
        :cols="girdLayoutCfg.cols"
        :right-to-left="girdLayoutCfg.rightToLeft"
        :margin="girdLayoutCfg.margin"
        @layout-created="layoutCreatedEvent"
        @layout-before-mount="layoutBeforeMountEvent"
        @layout-mounted="layoutMountedEvent"
        @layout-ready="layoutReadyEvent"
        @layout-updated="layoutUpdatedEvent"
      >
        <grid-item
          v-for="(item, index) in layoutList"
          :static="item.static || gridItemCfg.static"
          :x="item.x"
          :y="item.y"
          :w="item.w || getKindWidth(item, 'min')"
          :h="item.h || getKindHeight(item, 'min')"
          :i="item.i"
          :key="item.i"
          :min-w="item.minW || getKindWidth(item, 'min') || gridItemCfg.minW"
          :max-w="item.maxW || getKindWidth(item, 'max') || gridItemCfg.maxW"
          :min-h="item.minH || getKindHeight(item, 'min') || gridItemCfg.minH"
          :max-h="item.maxH || getKindHeight(item, 'max') || gridItemCfg.maxH"
          :is-draggable="item.isDraggable || gridItemCfg.isDraggable"
          :is-resizable="item.isResizable || gridItemCfg.isResizable"
          :drag-allow-from="item.dragAllowFrom || gridItemCfg.dragAllowFrom"
          :drag-ignore-from="item.dragIgnoreFrom || gridItemCfg.dragIgnoreFrom"
          :resize-ignore-from="item.resizeIgnoreFrom || gridItemCfg.resizeIgnoreFrom"
          @resize="handleResizeEvent($event, item)"
          @move="moveEvent"
          @resized="resizedEvent"
          @moved="movedEvent"
        >
          <el-card v-loading="getItemIsLoading(item)" :body-style="{ padding: modulePadding + 'px',height: '100%' }" :style="getModuleStyle(item)" class="module-card-wrap" shadow="never">
            <div class="no-drag">
              <module-item
                :ref="'moduleRef'+getInfo(item, 'id')"
                :rows="getRows(item)"
                :columns="getColumns(item)"

                :module-item-data="dataInfoObj[item.i]||{}"
                :chart-config="chartConfig"
                :is-fullscreen="isFullscreen"
                :ref-id="item.i"
                :theme="chartsTheme"
                :tag-for-resize="getTagForResize(item.i)"
                :is-data-zoom="!!chartConfig.isDataZoom"
                :chart-index="index"
                :is-can-edit="canEdit"
                :can-edit="showAdvanced && canEdit"
                :show-area-max-height="getShowAreaMaxHeight(item)"
                change-btn-group-class="chart-change-btn"
                @handelFilterChange="handelFilterChange"
              />
            </div>
            <div v-if="canEdit" class="vue-draggable-handle">
              <span style="flex:1;"/>
              <div class="chart-opeator-container">
                <div class="chart-opeator-item move"/>
                <el-tooltip content="引用新建模块" placement="top">
                  <div class="chart-opeator-item copy" @click="toEditModule(index, 'copy')"/>
                </el-tooltip>
                <el-tooltip content="编辑模块" placement="top">
                  <div class="chart-opeator-item edit" @click="toEditModule(index)" />
                </el-tooltip>
                <el-tooltip content="删除模块" placement="top">
                  <div class="chart-opeator-item delete" @click="toRemoveModule(index)"/>
                </el-tooltip>
              </div>
              <!-- <el-button-group class="fr" style="min-width: 130px">
                <el-button icon="el-icon-rank" size="mini" plain style="pointer-events: none"/>
                <el-button icon="el-icon-paperclip" size="mini" plain @click="toEditModule(index, 'copy')"/>
                <el-button icon="el-icon-edit" size="mini" plain @click="toEditModule(index)"/>
                <el-button icon="el-icon-delete" size="mini" plain @click="toRemoveModule(index)"/>
              </el-button-group> -->
            </div>
          </el-card>
        </grid-item>
      </grid-layout>
    </template>
    <el-button-group :class="{ 'show-advan': showAdvanced}" class="advanced-switch-wrap">
      <el-button class="advanced-switch" size="small" @click="showAdvanced = !showAdvanced">高级编辑</el-button>
      <el-button class="advanced-switch" size="small" @click="isDataZoom = !isDataZoom">缩放</el-button>
      <el-button :loading="updateDataLoading" class="advanced-switch" size="small" style="margin-left:10px;" @click="dataUpdate">更新</el-button>
    </el-button-group>
    <ConfigSetting ref="configSetting" :tab-id="activeChartTab" @getConfig="getConfig" />
    <todayVisitors ref="todayVisitors" />
    <messageConfirm ref="confirmMsgRef" />
  </div>
</template>
<script>
import VueGridLayout from 'vue-grid-layout'; // 使用说明：https://github.com/jbaysolutions/vue-grid-layout/blob/master/README-zh_CN.md
import ModuleItem from '@/components/DashboardPage/ModuleItem';
import ConfigSetting from '@/components/DashboardPage/configSetting';
import DashboardListTab from '@/components/DashboardPage/DashboardListTab/index.vue';
import ChatOverview from '@/components/DashboardPage/DashboardListTab/ChatOverview.vue';
import emptyImg from '@/assets/empty-table-data.png';
import todayVisitors from '@/components/DashboardPage/todayVisitors';
import MoreOpeator from '@/components/Common/baseComponent/moreOpeator';
import dashboardMixin from './mixin/dashboardLayout';
import styleMixin from './mixin/style';
import refresh from './mixin/refresh';
import messageConfirm from '@/components/Common/messageConfirm';
import FilterPopover from '@/components/DashboardPage/filterPopover';
import adsorbBtnIcon from '@/assets/chartsTheme/adsorbButton/adsorb-btn-icon.png';
import fullscreenBtnIcon from '@/assets/chartsTheme/adsorbButton/fullscreen-btn-icon.png';
import adjustBtnIcon from '@/assets/chartsTheme/adsorbButton/adjust-btn-icon.png';
import filterBtnIcon from '@/assets/chartsTheme/adsorbButton/filter-btn-icon.png';
import { TAG_MODULE_STYLE, HOME_ITEM_TYPE } from '@/utils/const/echarts';
import { hasRouteAuth } from '@/utils/permission';
import {
  getChartTableDetail, editChartTableLayout, clearCharts,
  getChartTableLayout, removeChartTable, getChartConfig, updateData, batchCreateChartTable
} from '@/api/reportManage';
import { EventBus } from '@/utils/eventBus';
import { mapState } from 'vuex';
import { showModal } from '@/utils/message';
import ElMessage from '@/utils/message';

export default {
  name: 'Dashbord',
  components: {
    GridLayout: VueGridLayout.GridLayout,
    GridItem: VueGridLayout.GridItem,
    ModuleItem,
    ConfigSetting,
    FilterPopover,
    messageConfirm,
    DashboardListTab,
    todayVisitors,
    ChatOverview,
    MoreOpeator
  },
  mixins: [dashboardMixin, refresh, styleMixin],
  data() {
    return {
      adsorbBtnIcon,
      fullscreenBtnIcon,
      filterBtnIcon,
      adjustBtnIcon,
      emptyImg,
      updateDataLoading: false,
      dataInfoObj: {},
      showAdvanced: false,
      isDataZoom: false,
      chartsTheme: true,
      listLoading: true,
      canEdit: false,
      cacheDeleteIDs: null,
      chartsIds: [],
      activeChartTab: '',
      isFullscreen: false,
      globalFilter: {},
      isEdit: false,
      isHideAdsorbBall: true,
      mobileIds: [],
      pcIds: [],
      allChartTab: [],
      chartConfigAll: {}, // 包含移动端和PC端的样式
      editMobileMode: false, // 在 PC 端时，是否开启编辑移动端模式
      fromConfigSettingMobile: false, // 移动端编辑模式时进入视图编辑后退出是否返回移动端编辑模式
      isShow: true,
      permissionDenied: false
    };
  },
  computed: {
    ...mapState({
      'showMobilePage': state => state.app.showMobilePage,
      'sidebar': state => state.app.sidebar
    }),
    chartConfig() {
      const config = this.chartConfigAll;
      // 兼容旧数据
      if (!Object.hasOwnProperty.call(config, 'pcStyle') && !Object.hasOwnProperty.call(config, 'mobileStyle')) {
        return config;
      }
      if (this.showMobilePage || this.editMobileMode) {
        return config.mobileStyle || {};
      } else {
        return config.pcStyle || {};
      }
    },
    modulePadding() {
      const padding = this.chartConfig.modulePadding || this.chartConfig.modulePadding === 0 ? this.chartConfig.modulePadding : 12;
      return padding;
    },
    chartConfigStyle() {
      const chartConfig = this.chartConfig;
      const style = {};
      if (chartConfig.backgroundImage) {
        style.backgroundImage = `url(${chartConfig.backgroundImage})`;
      } else {
        style.backgroundColor = '#f5f5f5';
      }
      if (chartConfig.backgroundSize === '拉伸') {
        style.backgroundSize = '100% 100%';
        style.backgroundRepeat = 'no-repeat';
      } else if (chartConfig.backgroundSize === '平铺') {
        style.backgroundRepeat = 'repeat';
      } else if (chartConfig.backgroundSize === '居中') {
        style.backgroundRepeat = 'no-repeat';
        style.backgroundPosition = 'center center';
      }
      // 移动端和移动端编辑模式必为自适应
      if (!this.showMobilePage && chartConfig.isResponsive === false && (chartConfig.canvasWidth || chartConfig.canvasWidth === 0)) {
        style.width = chartConfig.canvasWidth + 'px';
      }
      if (this.editMobileMode) style.width = '375px';
      style.paddingTop = (this.canEdit || !this.isHideAdsorbBall) ? '80px' : '48px';
      return style;
    },
    hasEditPermission() {
      return hasRouteAuth('chart:departEdit:all');
    },
    sidebarStatus() {
      const app = this.$store.state.app;
      return app.device !== 'mobile' && app.sidebar.opened;
    },
    isFirstPage() { // 是否首页
      const selectItem = this.allChartTab.find(it => it.id === this.activeChartTab);
      return selectItem ? selectItem.isFirstPage === 1 : false;
    }
  },
  watch: {
    sidebarStatus: {
      handler(newVal, oldVal) {
        this.refreshResizeTag();
      },
      immediate: false
    }
  },
  destroyed() {
    window.onresize = null;
  },
  mounted() {
    this.$store.dispatch('GetColorList');
    this.beforeInit();
    const { tabId, edit, editMobileMode } = this.$route.query;
    const activeChartTab = tabId;
    if (edit) this.isEdit = true;
    if (editMobileMode) this.editMobileMode = true;
    if (activeChartTab) this.activeChartTab = Number(activeChartTab);
    window.onresize = this.setFullScreen;
    EventBus.$on('showTodayVisitors', () => {
      this.$refs.todayVisitors.openDialog();
    });
  },
  beforeRouteLeave(to, from, next) {
    this.clearRefreshInterval();
    if (this.hasChanged()) {
      this.onChangeEdit(false, () => setTimeout(next, 100));
    } else {
      next();
    }
  },
  methods: {
    hasRouteAuth,
    handleTabClick(tab) {
      // this.activeChartTab = tab.toString();
      this.beforeInit(() => {
        this.activeChartTab = tab;
        if (location.hash) {
          const hash = location.hash.split('?')[0];
          window.history.replaceState({}, '', hash + `?tabId=${tab}`);
        }
        this.isEdit = false;
        this.isHideAdsorbBall = true;
      });
    },
    toggleShow(isShow) {
      this.isShow = isShow;
      this.getLayoutList();
    },
    init() {
      this.cacheDeleteIDs = [];
      this.layoutList = [];
      this.dataInfoObj = {};
      this.cacheLayout = null;
      this.canEdit = false;
      this.readyLayout = false;
      this.tagsForResize = {};
      if (!this.fromConfigSettingMobile) {
        this.editMobileMode = false;
      } else {
        this.fromConfigSettingMobile = false;
      }
      if (this.activeChartTab === -10) {
        // activeChartTab: -10 图表概览
        this.chartConfigAll = {};
        this.chartsIds = [];
        return;
      }
      this.listLoading = true;
      if (!Number(this.activeChartTab) || this.allChartTab.length === 0) {
        this.$refs.DashboardListTabRef.getChartTab((res, err = {}) => {
          this.allChartTab = res.data || [];
          this.permissionDenied = err.code === 403;
          if (this.permissionDenied) this.activeChartTab = -10;
          this.getLayoutList();
          this.getConfig();
          this.$refs.filterPopoverRef && this.$refs.filterPopoverRef.getFilter(true, this.activeChartTab, true);
        });
      } else {
        this.getLayoutList();
        this.getConfig();
        this.$nextTick(() => {
          this.$refs.filterPopoverRef && this.$refs.filterPopoverRef.getFilter(true, this.activeChartTab, true);
        });
      }
    },
    getTabList() {
      this.$refs.DashboardListTabRef.getChartTab((res, err = {}) => {
        this.allChartTab = res.data || [];
        this.permissionDenied = err.code === 403;
      });
    },
    beforeInit(callback = null) {
      if (this.hasChanged()) {
        this.onChangeEdit(false, () => {
          if (callback) callback();
          this.init();
        });
      } else {
        if (callback) callback();
        this.init();
      }
    },
    getItemIsLoading(item) {
      const value = this.dataInfoObj[item.i];
      return !value && value !== '';
    },
    getShowAreaMaxHeight(item) {
      const h = item.h || this.getKindHeight(item, 'min');
      const rowHeight = this.girdLayoutCfg.rowHeight;
      const marginModule = this.girdLayoutCfg.margin[1];
      // return h * (rowHeight + marginModule) - marginModule - (this.modulePadding * 2) - (this.getInfo(item, 'kind') === 1 ? 0 : 32);
      return h * (rowHeight + marginModule) - marginModule - (this.modulePadding * 2);
    },
    getRows(item) {
      const dataInfo = this.dataInfoObj[item.i];
      return dataInfo && dataInfo.tableData && dataInfo.tableData.rows || [];
    },
    getColumns(item) {
      const dataInfo = this.dataInfoObj[item.i];
      return dataInfo && dataInfo.tableData && dataInfo.tableData.columns || [];
    },
    getInfo(item, key) {
      const dataInfo = this.dataInfoObj[item.i];
      return dataInfo && dataInfo[key];
    },
    getKindHeight(item, key) {
      return this.itemKindsHeights[this.getInfo(item, 'kind') || 0][key];
    },
    getKindWidth(item, key) {
      return this.itemKindsWidths[this.getInfo(item, 'kind') || 0][key];
    },
    cancelEdit() {
      this.canEdit = false;
      if (this.hasChanged()) {
        this.onChangeEdit(false, is => is ? null : this.init(), true);
      }
    },
    saveEdit() {
      if (this.hasChanged()) {
        this.onChangeEdit(false, is => is ? null : this.init(), true);
      } else {
        this.canEdit = false;
      }
    },
    hasChanged() {
      if (!this.cacheLayout) {
        return false;
      }
      const newLayout = this.getCurrentLayout();
      if (JSON.stringify(newLayout) === JSON.stringify(this.cacheLayout)) return false;
      else return newLayout;
    },
    setExpanded(active) {
      if (active) {
        this.onChangeEdit(active);
      } else {
        this.cancelEdit();
      }
    },
    onChangeEdit(active, callback, isAgain = false) {
      this.canEdit = active;
      if (active) {
        if (!this.cacheLayout) this.cacheLayout = this.getCurrentLayout();
        return;
      }
      const newLayout = this.getCurrentLayout();
      if (JSON.stringify(newLayout) === JSON.stringify(this.cacheLayout)) return;
      const hasDelete = this.cacheDeleteIDs && this.cacheDeleteIDs.length;
      const msg = (isAgain ? '请再次' : '') + (hasDelete ? '确认是否保存新布局和已删图表？' : '确认是否保存新布局？');
      this.showMessage(msg).then(async() => {
        if (hasDelete) {
          const canDelete = await this.removeModule();
          if (!canDelete) {
            if (callback) callback(false);
            return;
          }
        }
        this.editChartTableLayout(newLayout).then(() => { if (callback) callback(true); });
      }).catch(action => {
        if (action === 'cancel' || action === 'close') this.$message.info('您已取消保存!');
        if (callback) callback(false);
      });
    },
    toCreatModule() {
      const query = { tabId: this.activeChartTab };
      const { isFirstPage } = this.$route.query;
      if (this.isFirstPage || isFirstPage) {
        query.isFirstPage = 1;
      }
      if (this.editMobileMode) query.editMobileMode = this.editMobileMode;
      this.$router.push({
        name: 'createChart',
        query
      });
    },
    toEditModule(index, type = 'edit') {
      const query = { tabId: this.activeChartTab, type };
      const { isFirstPage } = this.$route.query;
      if (this.isFirstPage || isFirstPage) {
        query.isFirstPage = 1;
      }
      if (this.editMobileMode) query.editMobileMode = this.editMobileMode;
      this.$router.push({
        name: 'editChart',
        params: { id: this.layoutList[index].i },
        query
      });
    },
    toRemoveModule(index) {
      this.cacheDeleteIDs.push(this.layoutList[index].i);
      // this.cacheDeleteIDs.push(this.layoutList[index]);
      this.layoutList.splice(index, 1);
      this.$message.success('本地已删除，点击保存后提交');
    },
    async removeModule() {
      return new Promise((resolve, reject) => {
        removeChartTable({ ids: this.cacheDeleteIDs }).then(res => {
          this.$message.success('图表删除保存成功！');
          this.cacheDeleteIDs = [];
          resolve(true);
        }, result => {
          console.info('删除图表', result);
          resolve(false);
        }).catch(e => {
          console.error(e);
          resolve(false);
        });
      });
    },
    getLayoutList(callback) {
      getChartTableLayout({ tabId: this.activeChartTab }).then(res => {
        this.chartsIds = [];
        if (res.data && res.data.showChartsIds && res.data.showChartsIds.length) {
          this.chartsIds = res.data.showChartsIds.reverse();
        }
        this.handleClassify();
        if (this.showMobilePage || this.editMobileMode) {
          this.getChartData(this.mobileIds, !this.showMobilePage);
        } else {
          this.getChartData(this.pcIds);
        }
        if (callback) callback();
      }, result => {
        this.listLoading = false;
      }).catch(e => {
        console.error(e);
      });
    },
    getCurrentLayout() {
      return this.layoutList.map((item, index) => {
        const { i, x, y, w, h, isMobile } = item;
        return {
          id: i,
          layout: JSON.stringify({ x, y, w, h }),
          isMobile
        };
      });
    },
    editChartTableLayout(layoutList) {
      return new Promise((resolve, reject) => {
        if (!layoutList) layoutList = this.getCurrentLayout();
        const params = {
          tabId: this.activeChartTab,
          showChartsIds: layoutList
        };
        editChartTableLayout(params).then(res => {
          this.$message.success('保存布局成功');
          this.cacheLayout = null;
          resolve();
        }, result => {
        // this.$message.error(result.message);
        }).catch(e => {
          reject();
          console.error(e);
        });
      });
    },
    handelFilterChange({ params, index }, callback) {
      this.getChartTableDetail(params.id, index, params).then((res) => {
        callback && callback(res);
      }).catch(() => {
        callback && callback();
      });
    },
    handelAllChange(data) {
      const params = this.globalFilter;
      this.$nextTick(() => {
        this.chartsIds.forEach((i, index) => {
          if (this.$refs['moduleRef' + i.id] && this.$refs['moduleRef' + i.id][0]) {
            this.$refs['moduleRef' + i.id][0].setGlobalParams(params);
          }
        });
      });
    },
    // getConfig(reset = false) {
    getConfig(emitObj) {
      getChartConfig({ id: this.activeChartTab }).then(res => {
        if (res.data) {
          try {
            this.chartConfigAll = JSON.parse(res.data.config || '{}');
          } catch (error) {
            this.chartConfigAll = {};
          }
          emitObj && (this.fromConfigSettingMobile = emitObj.isMobile);
          if (emitObj && emitObj.reset) {
            this.beforeInit();
          }
        }
      });
    },
    setFullScreen() {
      const isFull = window.fullScreen || document.webkitIsFullScreen;
      this.isFullscreen = isFull;
    },
    getFullScreen() {
      // 利用屏幕分辨率和window对象的内高度来判断兼容IE
      // const winFlag = window.innerHeight === window.screen.height;
      // 利用window全屏标识来判断 -- IE无效
      return window.fullScreen || document.webkitIsFullScreen;
    },
    switchFullscreen() {
      const fullarea = document.getElementById('fullarea');
      if (this.getFullScreen()) { // 退出全屏
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.webkitCancelFullScreen) {
          document.webkitCancelFullScreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        }
      } else { // 进入全屏
        if (fullarea.requestFullscreen) {
          fullarea.requestFullscreen();
        } else if (fullarea.webkitRequestFullScreen) {
          fullarea.webkitRequestFullScreen();
        } else if (fullarea.mozRequestFullScreen) {
          fullarea.mozRequestFullScreen();
        } else if (fullarea.msRequestFullscreen) {
          // IE11
          fullarea.msRequestFullscreen();
        }
      }
    },
    toEditConfig() {
      if (this.$refs.configSetting) this.$refs.configSetting.openDialog(this.chartConfigAll, this.showMobilePage || this.editMobileMode);
    },
    toClear() {
      showModal('确认清空所有图表配置？').then(() => {
        clearCharts(this.activeChartTab).then(res => {
          if (res.code === 200) {
            this.$message.success('操作成功');
            if (location.hash) {
              const hash = location.hash.split('?')[0];
              window.history.replaceState({}, '', hash + `?tabId=${this.activeChartTab}`);
            }
            this.isEdit = false;
            this.isHideAdsorbBall = true;
            this.init();
          }
        }).catch(err => {
          console.log(err);
        });
      });
    },
    dataUpdate() {
      this.updateDataLoading = true;
      updateData().then((res) => {
        this.showAdvanced = false;
        this.updateDataLoading = false;
        this.$message.success('更新成功');
      });
    },
    handleResizeEvent(e, data) {
      const { moduleType, homeModuleType } = this.dataInfoObj[data.i];
      // 圆环图
      const ringModuleArr = [TAG_MODULE_STYLE.RING_MODULE, TAG_MODULE_STYLE.PIE_MODULE, TAG_MODULE_STYLE.HISTOGRAM_MODULE];
      // 首页-待办、快捷入口模块
      const homeModuleArr = [HOME_ITEM_TYPE.TO_DO, HOME_ITEM_TYPE.QUICK_ENTRY];
      if (ringModuleArr.includes(moduleType) || homeModuleArr.includes(homeModuleType)) {
        const refName = 'moduleRef' + this.getInfo(data, 'id');
        this.$refs[refName] && this.$refs[refName][0] && this.$refs[refName][0].resetEchart();
      }
    },
    handleEditClick() {
      this.onChangeEdit(true);
    },
    getNameFromUniqueId(uniqueId) {
      if (!uniqueId) return uniqueId;
      if (Array.isArray(uniqueId)) {
        return uniqueId.map(i => {
          if (i.indexOf('#') < 0) return i;
          return i.split('#')[0];
        });
      }
      if (uniqueId.indexOf('#') < 0) return uniqueId;
      // uniqueId 的格式为 ${name}#${sourceId}
      return uniqueId.split('#')[0];
    },
    // 切换编辑移动端模式
    toConfigMobile(isPc = true) {
      if (this.editMobileMode === !isPc) return;
      const tip = isPc ? '是否切换到PC端配置？' : '是否切换到移动端配置？';
      this.showMessage(tip).then(_ => {
        this.editMobileMode = !isPc; // 切换模式
        const newLayout = this.getCurrentLayout();

        this.getLayoutList(() => {
          this.$nextTick(() => {
          // 更新 cacheLayout
            this.cacheLayout = this.getCurrentLayout();
          });
        });
        if (JSON.stringify(newLayout) === JSON.stringify(this.cacheLayout)) return;
        const hasDelete = this.cacheDeleteIDs && this.cacheDeleteIDs.length;
        this.editChartTableLayout(newLayout);
        if (hasDelete) this.removeModule();
        // 如果进入移动端编辑模式，则继续使 canEdit 为 true
        if (this.editMobileMode) {
          this.$nextTick(() => {
            this.canEdit = true;
          });
        }
      });
    },
    // 复制PC端到移动端
    async toCopyMobile() {
      if (this.pcIds.length === 0) {
        ElMessage.warning('该PC端下暂时没有图表');
        return;
      }
      this.showMessage('是否复制PC端图表配置内容到移动端页面？').then(async(_) => {
        // 复制时直接批量新增
        try {
          const params = {
            ids: this.pcIds.map(item => item.id),
            tabId: this.activeChartTab,
            isMobile: 1
          };
          const res = await batchCreateChartTable(params);
          if (res.code === 200) {
            // 重新获取tab下的图表id
            this.getLayoutList();
            this.$nextTick(() => {
              this.canEdit = true;
            });
          }
        } catch (err) {
          console.log(err);
        }
      });
    },
    handleClassify() {
      const ids = this.chartsIds;
      if (!ids) return;
      this.mobileIds = ids.filter(item => {
        return item.isMobile && item.isShow === this.isShow;
      });
      this.pcIds = ids.filter(item => {
        return !item.isMobile && item.isShow === this.isShow;
      });
    },
    /**
     * 获取数据
     */
    getChartData(ids, isChangeEdit = 0) {
      const dataInfoObj = {};
      const tagsForResize = {};
      this.layoutList = ids.map((item, index) => {
        const layout = { i: item.id, ...JSON.parse(item.layout || '{ "x": 0, "y": 0, "w": 12, "h": 0}') };
        if (!layout.x && !layout.y && !layout.h) layout.h = this.itemKindsHeights[0].min;
        dataInfoObj[item.id] = null;
        tagsForResize[item.id] = false;
        return layout;
      });
      const _that = this;
      this.dataInfoObj = dataInfoObj;
      ids.reverse();
      Promise.all(ids.map((item, index) => {
        const itemId = ids[index].id;
        return _that.getChartTableDetail(itemId, index, { isInit: true });
      })).then(() => {
        // _that.dataInfoObj = dataInfoObj;
        _that.layoutList.forEach((layoutItem, index) => {
          const minH = _that.getKindHeight(layoutItem, 'min');
          const minW = _that.getKindWidth(layoutItem, 'min');
          if (!layoutItem.h || layoutItem.h < minH) layoutItem.h = minH;
          if (!layoutItem.w || layoutItem.w < minW) layoutItem.w = minW;
        });
        if (_that.$refs.gridLayout) _that.$refs.gridLayout.layoutUpdate();
      }).catch((error) => {
        console.error(error);
      });
      this.tagsForResize = tagsForResize;
      this.refreshInterval(); // 开启定时刷新数据
      this.listLoading = false;
      if (isChangeEdit && !this.fromConfigSettingMobile) {
        this.onChangeEdit(true); // 保存
      }
      // 从新建编辑页跳转，页面触发为编辑状态
      const { from, edit } = this.$route.query;
      if (from) {
        this.setExpanded(true);
        this.$route.query.from = '';
        if (location.hash) {
          const hash = location.hash.split('?')[0];
          let url = `?tabId=${this.activeChartTab}`;
          if (edit) url = url + '&edit=1';
          window.history.replaceState({}, '', hash + url);
        }
      }
    },
    getChartTableDetail(id, index, extendParams = {}) {
      const params = {
        id,
        ...extendParams
      };
      params.isInit = params.isInit || false;
      if (extendParams.beginTime) params.beginTime = extendParams.beginTime;
      if (extendParams.endTime) params.endTime = extendParams.endTime;
      if (extendParams.trendTimeType) params.trendTimeType = extendParams.trendTimeType;
      return getChartTableDetail(params).then(res => {
        if (res.data && res.data.xAxis) res.data.xAxis = this.getNameFromUniqueId(res.data.xAxis);
        if (res.data && res.data.yAxis) res.data.yAxis = this.getNameFromUniqueId(res.data.yAxis);
        if (res.data && res.data.yAxisCombo) res.data.yAxisCombo = this.getNameFromUniqueId(res.data.yAxisCombo);

        if (res.data && (res.data.type === 6 || res.data.type === 3)) {
          if (res.data.tableData.rows.length > 50) {
            res.data.tableData.rows.splice(50, res.data.tableData.rows.length);
          }
        }
        if (res.data) {
          const contrastText = (res.data.contrastTime && res.data.contrastTime !== '') ? res.data.contrastTime : '对比';
          const hasContrastTime = res.data.contrastTime && res.data.contrastTime !== '';
          const hasContrastTimeRange = res.data.contrastTimeRange && res.data.contrastTimeRange.length === 2;
          // 如果是对比折线图，需要删除数据中的多余列
          if (res.data.type === 13 && (hasContrastTime || hasContrastTimeRange)) {
            const xAxis = res.data.xAxis;
            let contrastXAxisIndex = -1;
            const xAxisIndex = res.data.tableData.columns.indexOf(xAxis);
            if (res.data.tableData.columns && res.data.tableData.columns.length) {
              res.data.tableData.columns = res.data.tableData.columns.filter((i, jindex) => {
                if (i !== `${contrastText}${xAxis}`) {
                  return true;
                }
                contrastXAxisIndex = jindex;
                return false;
              });
            }
            const contrastTimeArr = { YAxis: '', contrastText, items: [] };// 原时间 - 对比时间 映射表
            if (res.data.tableData.rows && res.data.tableData.rows.length) {
              res.data.tableData.rows.forEach(i => {
                if (i.length >= contrastXAxisIndex + 1) {
                  const datatemp = i.splice(contrastXAxisIndex, 1);
                  contrastTimeArr.items.push({ name: `${contrastText}${xAxis}`, time: i[xAxisIndex], contrastTime: datatemp[0] });
                }
              });
            }
            const extendYAxis = res.data.yAxis.map(i => {
              return `${contrastText}${i}`;
            });
            contrastTimeArr.YAxis = extendYAxis;
            res.data.contrastTimeArr = contrastTimeArr;
            if (extendYAxis && extendYAxis.length > 0)res.data.yAxis = res.data.yAxis.concat(extendYAxis);
          } else if (res.data.chartFilter && res.data.yAxis && res.data.yAxis.length && res.data.chartFilter.length > 1) {
            const yAxis = [];
            /**
             * 一个筛选组就会有一个数据，所以这里是为了根据筛选组同步增加 yAxis 的值，规则是 `晒选择名称-y轴名称`
             */
            for (let i = 0; i < res.data.yAxis.length; i++) {
              res.data.chartFilter.forEach(j => {
                yAxis.push(`${j.filterName}-${res.data.yAxis[i]}`);
              });
            }
            res.data.yAxis = yAxis;
          }
          // 格式化
          if (res.data.styleConfig) {
            res.data.styleConfig = JSON.parse(res.data.styleConfig);
          }
        }
        // 注入数据
        const itemData = res.data;
        if (itemData && itemData.yAxisCombo) {
          itemData.yAxis.push(itemData.yAxisCombo);
        }
        this.dataInfoObj[id] = null;
        this.$nextTick(() => {
          this.dataInfoObj[id] = itemData;
        });
        return { id, index, data: res.data };
      }).catch(e => {
        console.error(id, e);
        return { id, index, data: '' };
      });
    },
    showMessage(msg) {
      return new Promise((resolve, reject) => {
        const msgModel = this.isFullscreen ? this.$refs.confirmMsgRef.openConfirm : showModal;
        msgModel(msg, '', {}, true).then(() => {
          resolve();
        }).catch(action => {
          reject(action);
        });
      });
    },
    tabClick(item) {
      this.$refs.DashboardListTabRef.tabClick(item);
    }
  }
};
</script>
<style lang="scss" scoped>
  .total-app-container {
    width: 100%;
    background-color:#FBFBFD;
    min-height: calc(100vh - 65px);
    .edit-mobile-mode {
      position: fixed;
      color: #333;
      right: 0;
      bottom: 0;
      font-size: 12px;
    }
    &.total-app-container-mobile {
       min-height: calc(100vh - 116px);
    }
    &.theme-light {
      --main-bg: rgba(242,248,255,1);
      --card-bg: white;
      --resize-color: #4373FB;
    }
    &.theme-dark {
      --main-bg: #02135a;
      --card-bg: #010D35;
      --resize-color: white;
      .el-card {
        background-color: var(--card-bg);
      }
      .vue-grid-layout {
        border-radius: 10px;
        margin-top: 15px;
      }
      ::v-deep{
        .el-loading-mask {
          background-color: var(--card-bg);
        }
        &.v-charts-data-empty {
          background-color: var(--card-bg);
        }
        &> .vue-resizable-handle {
          border: 1px solid white;
        }
        &.item-header {
          color: #cccccc;
        }
        &.tag-item {
          .item-value {
            color: white;
          }
        }
        &.table-item {
          .el-table {
            background-color: #010D35;
            .table-header>th {
              background-color: #02135a;
            }
          }
          .double-row {
            background: #4373FB;
          }
          .single-row {
            background: #010D35;
          }
        }
      }
    }

    .edit-wrap {
      display:flex;
      justify-content: flex-end;
      align-items: center;
      height: 32px;
      p {
        color: #606265;
      }
    }
    .empty-card-container {
      padding: 15px;
    }
    .empty-card-wrap {
      border-radius: 12px;
      border: none;
      p {
        color: #606265;
        text-align: center;
      }
    }
    ::v-deep .chart-change-btn {
      position: absolute;
      right: 120px;
      top: -24px;
      width: 113px;
    }

    .advanced-switch-wrap {
      position: absolute;
      left: 2px;
      bottom: 2px;
      font-size: 12px;
      transform: scale(0.5);
      .advanced-switch {
        padding: 2px;
        color: transparent;
        background-color: transparent;
        border: none;
      }
      &.show-advan {
        .advanced-switch {
          color: #000;
          border: 1px solid #000;
        }
      }
    }

    /*===== 以下拖动布局相关 =====*/

    // .vue-grid-layout {
    //   // background: var(--main-bg);
    //   background: var(--main-bg);
    // }

    .vue-grid-item {
      /*border-radius: 12px;*/
      /*border: 1px solid red;*/
      ::v-deep .vue-resizable-handle {
        z-index: 5000;
        position: absolute;
        width: 10px;
        height: 10px;
        bottom: 8px;
        right: 8px;
        /*background: url('');*/
        /*background-position: bottom right;*/
        /*background-size: 60%;*/
        /*padding: 0 8px 8px 0;*/
        /*background-repeat: no-repeat;*/
        /*background-origin: content-box;*/
        box-sizing: border-box;
        background: none;
        border-width: 0 2px 2px 0;
        border-style: solid;
        border-color: var(--resize-color);
        cursor: se-resize;
      }
    }
    // .vue-grid-item:not(.vue-grid-placeholder) {
    //   /*background: black;*/
    //   /*border: 1px solid red;*/
    // }
    ::v-deep .vue-grid-item.vue-grid-placeholder {
      background: #406eff;
      opacity: .4;
    }
    .vue-grid-item.resizing {
      opacity: 0.9;
    }

    .vue-grid-item.static {
      background: lightskyblue;
    }

    .vue-grid-item .module-card-wrap {
      font-size: 24px;
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      margin: auto;
      height: 100%;
      width: 100%;
      border: none;
      &:hover {
        &::v-deep {
          .filter-img,.fresh-img {
            display: block;
          }
          .export-container {
            display: block;
          }
        }
      }
    }

    .vue-grid-item .no-drag {
      /*height: 100%;*/
      width: 100%;
      height: 100%;
    }

    .vue-grid-item .minMax {
      font-size: 12px;
    }

    .vue-grid-item .add {
      cursor: pointer;
    }

    .vue-draggable-handle {
      position: absolute;
      z-index: 11;
      width: 100%;
      height: auto;
      top: 0;
      left: 0;
      background-position: bottom right;
      padding: 8px;
      /*background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle cx='5' cy='5' r='5' fill='#999999'/></svg>") no-repeat;*/
      /*background-repeat: no-repeat;*/
      background-origin: content-box;
      box-sizing: border-box;
      cursor: move;
      display: flex;
      background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 30%,rgba(224, 224, 224, 0.5) 100%);
      // border-radius: 12px;
    }
  }
  .empty-img {
    width: 100px;
    display: block;
    margin: 0 auto;
    // margin-bottom: 25px;
  }
.scroll-container  {
  overflow-y: scroll;
}
.chart-opeator-container {
  display: flex;
  align-items: center;
  height: 30px;
}
.chart-opeator-item {
  width: 30px;
  height: 30px;
  background: #FFFFFF;
  border-radius: 8px;
  flex-shrink: 0;
  // opacity: 0.8;
  background-repeat: no-repeat;
  background-size: 20px 20px;
  background-position: center center;
  margin-left: 5px;
  cursor: pointer;
  &.move {
    background-image: url(../../../assets/chartsTheme/move.png);
    cursor: move;
  }
  &.copy {
    background-image: url(../../../assets/chartsTheme/copy.png);
  }
  &.edit {
    background-image: url(../../../assets/chartsTheme/editchart.png);
  }
  &.delete {
    background-image: url(../../../assets/chartsTheme/delete.png);
  }
  &:hover {
    &.move {
      background-image: url(../../../assets/chartsTheme/move-active.png);
    }
    &.copy {
      background-image: url(../../../assets/chartsTheme/copy-active.png);
    }
    &.edit {
      background-image: url(../../../assets/chartsTheme/editchart-active.png);
    }
    &.delete {
      background-image: url(../../../assets/chartsTheme/delete-active.png);
    }
  }
}
.adsorb-btn {
  position: fixed;
  top: 48px;
  right: 16px;
  background-color: #406EFF;
  color: #999;
  border-bottom-right-radius: 4px;
  border-bottom-left-radius: 4px;
  user-select: none;
  height: 10px;
  width: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
  cursor: pointer;
  > img {
    width: 6px;
    height: 6px;
  }
}
.expand-btn-group {
  display: flex;
  align-items: center;
  justify-content: right;
  position: fixed;
  top: 48px;
  right: 0;
  width: 100%;
  height: 48px;
  background-color: #f5f5f5;
  padding-right: 16px;
  z-index: 1;
  .system-group {
    position: absolute;
    left: 0;
    width: 64px;
    height: 24px;
    border-radius: 999px;
    border: 1px solid #DDDDDD;
    background: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    > i {
      display: block;
      flex: 1;
      text-align: center;
      cursor: pointer;
    }
    .system-highlight {
      background-color: #406eff;
      border-radius: 999px;
      height: 100%;
      line-height: 24px;
      color: #fff;
    }
  }
  .switch-group {
    position: absolute;
    width: 120px;
    height: 30px;
    background: #ffffff;
    border-radius: 4px;
    font-size: 12px;
    color: #999;
    box-shadow: 0px 1px 3px 0px rgba(0,0,0,0.12) inset;
    .item {
      display: flex;
      align-items: center;
      justify-content: center;
      flex-basis: 50%;
      line-height: 16px;
      z-index: 2;
      cursor: pointer;
    }
    .active {
      font-weight: 500;
      color: #fff;
    }
    .bg {
      position: absolute;
      left: 60px;
      top: 4px;
      width: 56px;
      height: 22px;
      background: #406eff;
      border-radius: 4px;
      transition: all 0.3s ease;
    }
  }
  .plain-btn {
    background: #fff;
    font-size: 14px;
    color: #406EFF;
    border-radius: 4px;
    border-color: #406EFF;
    box-sizing: border-box;
    img {
      width: 16px;
      height: 16px;
      margin-left: 4px;
    }
  }
  .plain-btn:hover {
    background-color: #406EFF;
    color: #fff;
    img {
      filter: brightness(99);
    }
  }
  .quiet-btn {
    border: 1px solid #DDDDDD;
    background: #fff;
    font-size: 14px;
    border-radius: 4px;
    color: #666;
  }
  .expend-btn {
    cursor: pointer;
    color:#406EFF;
    font-size: 14px;
    margin-left: 12px;
    &:hover {
      font-weight: bold;
    }
  }
  ::v-deep {
    .el-button {
      height: 32px;
      padding: 0 12px;
      font-size: 14px;
      margin-left: 12px;
    }
  }
}
</style>
<style lang="scss">
.float-edit-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  img {
    display: block;
    width: 16px;
    height: 16px;
  }
  .edit-img {
    width: 20px;
    height:20px;
  }
}
</style>
